
#include <Vector.h>

void Vector_DemoKeep(void** DS_ERROR)
{
    DS_PREPARE_CHECK(DS_RETURN_VOID);

    __data(Vector, v1);
    __data(Vector, v2);
    Vector_Init(v1, sizeof(int), DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);

    if(1)
    {
        Vector_Init(v2, sizeof(int), DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
        Vector_Deinit(v2, DS_ERROR);
    }
    __data(Vector, v3);
    Vector_Init(v3, sizeof(int), DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
    
    while(1)
    {

        __data(Vector, v4);
        Vector_Init(v4, sizeof(int), DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);

        if(1)
        {
            Vector_Deinit(v4, DS_ERROR);
            break;
            
        }

        if(2)
        {
            Vector_Deinit(v4, DS_ERROR);
            Vector_Deinit(v3, DS_ERROR);
            return ;
            
        }

        if(3)
        {
            Vector_Deinit(v4, DS_ERROR);
            Vector_Deinit(v3, DS_ERROR);
            DS_EXCEPTION_RETURN(DS_ERROR, NoneType, DS_RETURN_VOID);
            
        }
        Vector_Deinit(v4, DS_ERROR);
    }
    Vector_Deinit(v3, DS_ERROR);
}




void Vector_UnitTest(void** DS_ERROR)
{
    DS_PREPARE_CHECK(DS_RETURN_VOID);

    __data(Vector, arr);
    __data(Vector, arr1);
    Vector_Init(arr, sizeof(int), DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
    Vector_Init(arr1, sizeof(int), DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
    int i;
    int j;
    int* i_iter;
    int* j_iter;
    FOR_RANGE(i, 0, 5)
    {
        Vector_Push(arr, &i, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
        i_iter = Vector_At(arr, i, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
        UtEq(Ut_Int, "", *i_iter, i);
        int* i_iter;
        FOR_EACH_I(j, j_iter, Vector, arr1)
        {
            i_iter = Vector_At(arr, j, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
            UtEq(Ut_Int, "", *i_iter, *j_iter);
            
        }
        Vector_Push(arr1, &i, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
        
    }
    FOR_RANGE(i, 0, 5)
    {
        Vector_Pop(arr1, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
        FOR_EACH_I(j, j_iter, Vector, arr1)
        {
            i_iter = Vector_At(arr, j, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
            UtEq(Ut_Int, "", *i_iter, *j_iter);
            
        }
        Vector_Pop(arr, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
        
    }
    Vector_Deinit(arr1, DS_ERROR);
    Vector_Deinit(arr, DS_ERROR);
}




void Vector_Init(Vector_obj* self, int e_size,void** DS_ERROR)
{
    DS_PREPARE_CHECK(DS_RETURN_VOID);

    Vector_Clear(self, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
    
    COND_IS_TRUE = ( e_size < 0 );
    if(COND_IS_TRUE)
    {
        DS_EXCEPTION_RETURN(DS_ERROR, "e_size < 0", DS_RETURN_VOID);
        
    }
    Memory_Bzero(self, sizeof(Vector_obj), DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
    
    COND_IS_TRUE = ( e_size != 0 );
    if(COND_IS_TRUE)
    {
        Vector_SetESize(self, e_size, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
        Vector_EnsureMemoryEnough(self, 1, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
        
    }
}




void Vector_Deinit(Vector_obj* self,void** DS_ERROR)
{
    DS_PREPARE_CHECK(DS_RETURN_VOID);

    Vector_Clear(self, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
}




int Vector_ESize(Vector_obj* self,void** DS_ERROR)
{
    DS_PREPARE_CHECK(-1);

    return self->element_size;
}




int Vector_Capacity(Vector_obj* self,void** DS_ERROR)
{
    DS_PREPARE_CHECK(-1);

    COND_IS_TRUE = ( Vector_ESize(self, DS_ERROR) != 0 );                                        DS_EXCEPTON_CHECK("", -1);
    if(COND_IS_TRUE)
    {
        int byte = self->margin - self->start;
        return byte / Vector_ESize(self, DS_ERROR);                                        DS_EXCEPTON_CHECK("", -1);
        
    }
    return 0;
}




int Vector_Size(Vector_obj* self,void** DS_ERROR)
{
    DS_PREPARE_CHECK(-1);

    COND_IS_TRUE = ( Vector_ESize(self, DS_ERROR) != 0 );                                        DS_EXCEPTON_CHECK("", -1);
    if(COND_IS_TRUE)
    {
        int byte = self->end - self->start;
        return byte / Vector_ESize(self, DS_ERROR);                                        DS_EXCEPTON_CHECK("", -1);
        
    }
    return 0;
}




void Vector_SetESize(Vector_obj* self, int new_e_size,void** DS_ERROR)
{
    DS_PREPARE_CHECK(DS_RETURN_VOID);

    self->element_size = new_e_size;
}




void Vector_SetCapacity(Vector_obj* self, int capa,void** DS_ERROR)
{
    DS_PREPARE_CHECK(DS_RETURN_VOID);

    self->margin = self->start + Vector_ESize(self, DS_ERROR) * capa;                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
    
    COND_IS_TRUE = ( capa < Vector_Size(self, DS_ERROR) );                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
    if(COND_IS_TRUE)
    {
        Vector_SetSize(self, capa, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
        
    }
}




void Vector_SetSize(Vector_obj* self, int sz,void** DS_ERROR)
{
    DS_PREPARE_CHECK(DS_RETURN_VOID);

    self->end = self->start + Vector_ESize(self, DS_ERROR) * sz;                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
}




int Vector_NeedMemory(Vector_obj* self, int e_num,void** DS_ERROR)
{
    DS_PREPARE_CHECK(-1);

    return e_num * Vector_ESize(self, DS_ERROR);                                        DS_EXCEPTON_CHECK("", -1);
}




void Vector_EnsureMemoryEnough(Vector_obj* self, int e_number,void** DS_ERROR)
{
    DS_PREPARE_CHECK(DS_RETURN_VOID);

    int old_size = Vector_Size(self, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
    
    COND_IS_TRUE = ( Vector_Capacity(self, DS_ERROR) < e_number );                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
    if(COND_IS_TRUE)
    {
        int old_capacity = Vector_Capacity(self, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
        int new_capacity = Allocator_CapacityDoubleCalc(Vector_Capacity(self, DS_ERROR), e_number, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
        __data(Allocator, alloc);
        Allocator_Alloc(alloc, Vector_NeedMemory(self, new_capacity, DS_ERROR), DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
        
        COND_IS_TRUE = ( old_size > 0 );
        if(COND_IS_TRUE)
        {
            Allocator_LinearCopy(alloc, self->start, Vector_NeedMemory(self, Vector_Size(self, DS_ERROR), DS_ERROR), 0, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
            
        }
        self->start = Allocator_GetMemory(alloc, self->start, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
        Vector_SetSize(self, old_size, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
        Vector_SetCapacity(self, new_capacity, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
        Allocator_Free(alloc, DS_ERROR);
    }
}




void Vector_Clear(Vector_obj* self,void** DS_ERROR)
{
    DS_PREPARE_CHECK(DS_RETURN_VOID);

    Memory_free(self->start);
    self->end = self->start;
    self->margin = self->start;
}




void Vector_Reverse(Vector_obj* self,void** DS_ERROR)
{
    DS_PREPARE_CHECK(DS_RETURN_VOID);

    int n = Vector_Size(self, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
    int i;
    FOR_RANGE(i, 0, n)
    {

        if(i >= n - 1 - i)
        {
            break;
            
        }
        Vector_Swap(self, i, n - 1 - i, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
        
    }
}




void Vector_Swap(Vector_obj* self, int i1, int i2,void** DS_ERROR)
{
    DS_PREPARE_CHECK(DS_RETURN_VOID);

    char* d1 = Vector_At(self, i1, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
    char* d2 = Vector_At(self, i2, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
    Memory_Swap(d1, d2, Vector_ESize(self, DS_ERROR), DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
}




void* Vector_PopI(Vector_obj* self, int i,void** DS_ERROR)
{
    DS_PREPARE_CHECK(NULL);

    Vector_Swap(self, i, Vector_Size(self, DS_ERROR) - 1, DS_ERROR);                                        DS_EXCEPTON_CHECK("", NULL);
    return Vector_Pop(self, DS_ERROR);                                        DS_EXCEPTON_CHECK("", NULL);
}




void Vector_Push(Vector_obj* self, void* e,void** DS_ERROR)
{
    DS_PREPARE_CHECK(DS_RETURN_VOID);

    COND_IS_TRUE = ( Vector_ESize(self, DS_ERROR) == 0 );                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
    if(COND_IS_TRUE)
    {
        return ;
        
    }

    if(e == NULL)
    {
        DS_EXCEPTION_RETURN(DS_ERROR, "element is NULL", DS_RETURN_VOID);
        
    }

    if(self->start == NULL)
    {
        DS_EXCEPTION_RETURN(DS_ERROR, "array not init!", DS_RETURN_VOID);
        
    }
    Vector_EnsureMemoryEnough(self, Vector_Size(self, DS_ERROR) + 1, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
    Vector_PushUncheck(self, e, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
}




void Vector_PushCustom(Vector_obj* self, void* e, void* (*copy_proc)(void*,void**),void** DS_ERROR)
{
    DS_PREPARE_CHECK(DS_RETURN_VOID);

    Vector_EnsureMemoryEnough(self, Vector_Size(self, DS_ERROR) + 1, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
    Vector_PushUncheck(self, e, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
}




void* Vector_Pop(Vector_obj* self,void** DS_ERROR)
{
    DS_PREPARE_CHECK(NULL);

    COND_IS_TRUE = ( Vector_Size(self, DS_ERROR) > 0 );                                        DS_EXCEPTON_CHECK("", NULL);
    if(COND_IS_TRUE)
    {
        self->end -= Vector_ESize(self, DS_ERROR);                                        DS_EXCEPTON_CHECK("", NULL);
        
    }
    return self->end;
}




void Vector_PushUncheck(Vector_obj* self, void* e,void** DS_ERROR)
{
    DS_PREPARE_CHECK(DS_RETURN_VOID);

    COND_IS_TRUE = ( Vector_Capacity(self, DS_ERROR) <= Vector_Size(self, DS_ERROR) );                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
    if(COND_IS_TRUE)
    {
        DS_EXCEPTION_RETURN(DS_ERROR, "capacity not enough!", DS_RETURN_VOID);
        
    }
    
    COND_IS_TRUE = ( Vector_ESize(self, DS_ERROR) == 0 );                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
    if(COND_IS_TRUE)
    {
        DS_EXCEPTION_RETURN(DS_ERROR, "e_size = 0", DS_RETURN_VOID);
        
    }

    if(e == NULL)
    {
        DS_EXCEPTION_RETURN(DS_ERROR, "element pointer is NULL", DS_RETURN_VOID);
        
    }
    Memory_Copy(self->end, e, Vector_ESize(self, DS_ERROR), DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
    self->end += Vector_ESize(self, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
}




void* Vector_At(Vector_obj* self, int n,void** DS_ERROR)
{
    DS_PREPARE_CHECK(NULL);

    return Memory_SafeAt(self->start, Vector_ESize(self, DS_ERROR), n, Vector_Size(self, DS_ERROR), DS_ERROR);                                        DS_EXCEPTON_CHECK("", NULL);
}




void Vector_Delete(Vector_obj* self, void* e,void** DS_ERROR)
{
    DS_PREPARE_CHECK(DS_RETURN_VOID);

    int pos = Vector_Find(self, e, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
    
    COND_IS_TRUE = ( pos != DS_SIZE_NIL );
    if(COND_IS_TRUE)
    {
        Vector_PopI(self, pos, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
        
    }
}




int Vector_Find(Vector_obj* self, void* e,void** DS_ERROR)
{
    DS_PREPARE_CHECK(-1);

    int i;
    void* cur_e;
    FOR_EACH_I(i, cur_e, Vector, self)
    {
        
        COND_IS_TRUE = ( Memory_Same(cur_e, e, Vector_ESize(self, DS_ERROR), DS_ERROR) );                                        DS_EXCEPTON_CHECK("", -1);
        if(COND_IS_TRUE)
        {
            return i;
            
        }
        
    }
    return DS_SIZE_NIL;
}




ds_bool Vector_Same(Vector_obj* self, Vector_obj* that,void** DS_ERROR)
{
    DS_PREPARE_CHECK(-1);

    COND_IS_TRUE = ( Vector_Size(self, DS_ERROR) == Vector_Size(that, DS_ERROR) && Vector_ESize(self, DS_ERROR) == Vector_ESize(that, DS_ERROR) );                                        DS_EXCEPTON_CHECK("", -1);
    if(COND_IS_TRUE)
    {
        return Memory_Same(self->start, that->start, Vector_Size(self, DS_ERROR) * Vector_ESize(self, DS_ERROR), DS_ERROR);                                        DS_EXCEPTON_CHECK("", -1);
        
    }
    return 0;
}




void Vector_Merge(Vector_obj* self, Vector_obj* ext,void** DS_ERROR)
{
    DS_PREPARE_CHECK(DS_RETURN_VOID);

    COND_IS_TRUE = ( Vector_ESize(self, DS_ERROR) != Vector_ESize(ext, DS_ERROR) );                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
    if(COND_IS_TRUE)
    {
        DS_EXCEPTION_RETURN(DS_ERROR, "merge fail! e_size is different", DS_RETURN_VOID);
        
    }
    void* e;
    FOR_EACH(e, Vector, ext)
    {
        Vector_Push(self, e, DS_ERROR);                                        DS_EXCEPTON_CHECK("", DS_RETURN_VOID);
        
    }
}




void* Vector_Begin(Vector_obj* self,void** DS_ERROR)
{
    DS_PREPARE_CHECK(NULL);

    return self->start;
}




int Vector_NotEnd(Vector_obj* self, void* Iter,void** DS_ERROR)
{
    DS_PREPARE_CHECK(-1);

    if((char*)Iter < (char*)self->end)
    {
        return 1;
        
    }
    return 0;
}




void* Vector_Next(Vector_obj* self, void* iter,void** DS_ERROR)
{
    DS_PREPARE_CHECK(NULL);

    char* p = iter;
    return &p[self->element_size];
}




